﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using System.IO;
using System.Reflection;

namespace WebServer
{
	public static class IOUtility
	{
		/// <summary>
		/// Parses a given file path and returns the same path with any syntax errors removed.
		/// Syntax errors can include double seperators such as 'path/to//file.txt'
		/// </summary>
		/// <param name="initialPath">The initial path string to parse.</param>
		/// <param name="incFileName">Determines whether to append a file name to the parsed path. 
		/// This will only append if a file name is specified in the initial path.</param>
		/// <returns>The parsed path string with syntax errors removed.</returns>
		public static string GetSafeFilePath(string initialPath, bool incFileName)
		{
			StringBuilder sb = new StringBuilder();

			string[] split = initialPath.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);

			for (int i = 0; i < split.Length; i++)
			{
				if (i < split.Length - 1)
					sb.AppendFormat("{0}{1}", split[i], '/');
				else if (incFileName)
					sb.AppendFormat("{0}", split[i]);
				//else
				//	sb.AppendFormat("{0}{1}", split[i], '/');
			}

			return sb.ToString();
		}

		public static string GetUnusedFilePath(string path, string name)
		{
			string fullPath = GetSafeFilePath(path + "\\" + name, true);

			for (int i = 2; File.Exists(fullPath) && i <= 1000; ++i)
			{
				string[] split = name.Split(new char[] { '.' });

				if (split.Length == 2)
					fullPath = GetSafeFilePath(path + "\\" + split[0] + i + "." + split[1], true);
				else
					fullPath = GetSafeFilePath(path + "\\" + name + i, true);
			}

			return fullPath;
		}

		/// <summary>
		/// Invalidates the given file path and returns the cleaned path string with the appended file name. 
		/// Unlike SafeFilePath, this method does not remove syntax errors.
		/// </summary>
		/// <param name="filePath">The file path to invalidate.</param>
		/// <param name="fileName">The file name to append.</param>
		/// <returns>The cleaned path string with the appended file name.</returns>
		public static string GetValidFilePath(string filePath, string fileName)
		{
			string validPath = "";

			int lookup = filePath.Substring(filePath.Length - 1, 1).IndexOfAny(new char[] { '\\', '/' });
			bool hasEndSep = false;

			if (lookup != -1)
				hasEndSep = true;

			if (hasEndSep)
				filePath = filePath.Substring(0, lookup);

			string[] split = filePath.Split(new char[] { '\\', '/' });

			for (int i = 0; i < split.Length; i++)
			{
				validPath += split[i] + "\\";
			}

			if (fileName.Length > 0)
			{
				if (fileName.StartsWith("\\") || fileName.StartsWith("/"))
					fileName = fileName.TrimStart(new char[] { '\\', '/' });

				validPath += fileName;
			}
			else
			{
				if (validPath.EndsWith("\\") || validPath.EndsWith("/"))
					validPath = validPath.TrimEnd(new char[] { '\\', '/' });
			}

			return validPath;
		}

		public static FileInfo EnsureFile(string name)
		{
			return EnsureFile(name, false);
		}

		public static FileInfo EnsureFile(string name, bool replace)
		{
			return EnsureFile(new FileInfo(GetSafeFilePath(name, true)), replace);
		}

		public static FileInfo EnsureFile(FileInfo info)
		{
			return EnsureFile(info, false);
		}

		public static FileInfo EnsureFile(FileInfo info, bool replace)
		{
			try
			{
				if (info.Exists && replace)
				{
					info.Delete();
					info.Create().Close();
				}
				else
				{ info.Create().Close(); }
			}
			catch { }

			return info;
		}

		/// <summary>
		/// Parses a given directory path and returns the same path with any syntax errors removed.
		/// Syntax errors can include double seperators such as 'path/to//directory'
		/// </summary>
		/// <param name="initialPath">The initial path string to parse.</param>
		/// <returns>The parsed path string with syntax errors removed.</returns>
		public static string GetSafeDirectoryPath(string initialPath)
		{
			StringBuilder sb = new StringBuilder();

			string[] split = initialPath.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);

			for (int i = 0; i < split.Length; i++)
			{
				sb.AppendFormat("{0}{1}", split[i], i < split.Length ? "\\" : "");
			}

			return sb.ToString();
		}

		public static string GetUnusedDirectoryPath(string path, string name)
		{
			string fullPath = GetSafeDirectoryPath(path + "\\" + name);

			for (int i = 2; Directory.Exists(fullPath) && i <= 1000; ++i)
			{
				fullPath = GetSafeDirectoryPath(path + "\\" + name + i);
			}

			return fullPath;
		}

		/// <summary>
		/// Invalidates the given directory path and returns the cleaned path string. 
		/// Unlike GetSafeDirectoryPath, this method does not remove syntax errors.
		/// </summary>
		/// <param name="path">The directory path to invalidate.</param>
		/// <returns>The cleaned directory path string.</returns>
		public static string GetValidDirectoryPath(string path)
		{
			string validPath = "";

			int lookup = path.Substring(path.Length - 1, 1).IndexOfAny(new char[] { '\\', '/' });
			bool hasEndSep = false;

			if (lookup != -1)
				hasEndSep = true;

			if (hasEndSep)
				path = path.Substring(0, lookup);

			string[] split = path.Split(new char[] { '\\', '/' });

			for (int i = 0; i < split.Length; i++)
			{
				validPath += split[i] + "\\";
			}

			if (!validPath.EndsWith("\\") && !validPath.EndsWith("/"))
				validPath += "\\";

			return validPath;
		}

		public static DirectoryInfo EnsureDirectory(string name)
		{
			return EnsureDirectory(name, false);
		}

		public static DirectoryInfo EnsureDirectory(string name, bool replace)
		{
			return EnsureDirectory(new DirectoryInfo(GetSafeDirectoryPath(name)), replace);
		}

		public static DirectoryInfo EnsureDirectory(DirectoryInfo info)
		{
			return EnsureDirectory(info, false);
		}

		public static DirectoryInfo EnsureDirectory(DirectoryInfo info, bool replace)
		{
			try
			{
				if (info.Exists && replace)
				{
					info.Delete(true);
					info.Create();
				}
				else
				{ info.Create(); }
			}
			catch { }

			return info;
		}

		public static void EmptyDirectory(DirectoryInfo fromDir, bool incDirs)
		{
			try
			{
				FileInfo[] files = fromDir.GetFiles();

				foreach (FileInfo file in files)
				{
					try { file.Delete(); }
					catch { }
				}

				if (incDirs)
				{
					DirectoryInfo[] dirs = fromDir.GetDirectories();

					foreach (DirectoryInfo dir in dirs)
					{
						try { dir.Delete(true); }
						catch { }
					}
				}
			}
			catch
			{ }
		}

		public static void EmptyDirectory(DirectoryInfo fromDir, string mask, SearchOption option)
		{
			try
			{
				FileInfo[] files = fromDir.GetFiles(mask, option);

				foreach (FileInfo file in files)
				{
					try { file.Delete(); }
					catch { }
				}

				DirectoryInfo[] dirs = fromDir.GetDirectories(mask, option);

				foreach (DirectoryInfo dir in dirs)
				{
					try { dir.Delete(true); }
					catch { }
				}
			}
			catch
			{ }
		}

		/// <summary>
		/// Gets the base directory, relative the current Executing Assembly location.
		/// </summary>
		/// <returns>Fully qualified directory path for the the current Executing Assembly location.</returns>
		public static string GetBaseDirectory()
		{
			return GetSafeDirectoryPath(GetSafeFilePath(Assembly.GetExecutingAssembly().Location, false));
		}
	}
}
